﻿using System;
using System.Data;
using Oracle.DataAccess.Client;
using WorkFlow.DBProxy;

namespace WorkFlow.Engine.NSActivity.NSRoutes
{
    /// <summary>
    /// </summary>
    public class WfConditionTypeRoute
    {
        /// <summary>
        ///     条件合并
        ///     对于合并来说 只选择其中一条符合条件的路径 如果有多条,随机取一条
        /// </summary>
        /// 返回判定条件前的活动的id
        public void OrJoin(WfActivity act,int activatorID)
        {
            string sql =
                string.Format(
                    @"SELECT F_ID FROM T_ACTIVITIES t WHERE  exists (SELECT F_PRE_ACTIVITY FROM TR_PATHS p WHERE t.F_R_ACT_ID=p.F_PRE_ACTIVITY and F_AFTER_ACTIVITY = {0}) AND F_PROCESS_ID={1} AND F_STATUS={2}",
                    act.ID, act.ProcessId, WfFieldCode.DbCompleteState);

            //如果所有前置条件都为假,让条件合并进入就绪状态
            if (DB.GetFirstField(sql) == null)
            {
                act.Ready(activatorID);
                return;
            }
            //如果前面的条件有一个为真
            if (act.Status != WfFieldCode.DbReadyState) act.Ready(activatorID);
            act.Run(); //如果在调用complete()前活动实例的状态不为runState,将不会执行complete()
            act.Complete();
        }

        /// <summary>
        ///     条件分支
        /// </summary>
        public void OrSplit(WfActivity act,int activatorID, int? inputValue)
        {
            #region 判断要选择的路径或要设置的路径

            DataTable dt = DB.MapToDataTable(string.Format(@"
                                         select a.f_id as ACT_ID, (select f_id from t_activities where  f_r_act_id = p.f_after_activity and f_process_id={0}) as  NEXTACT,c.f_express as EXPRESS,
                                        a.f_input_value as INPUT_VALUE,c.f_is_need_input as IS_NEED_INPUT,
                                        C. f_para_name AS PARA_NAME
                                        from  tr_activities ra inner join tr_paths p on ra.f_id=p.f_pre_activity
                                        inner join tr_conditions c on c.f_id=p.f_condition_id
                                        inner join t_activities a on a.f_r_act_id=ra.f_id
                                        where a.f_id={1} ", act.ProcessId, act.ID));
            if (dt == null || dt.Rows.Count == 0) return;

            string parm = string.Empty;

            //如果该条件分支需要输入值 设置输入值  一般情况下都必须有输入值 否则怎么条件判断
            if (Convert.ToInt32(dt.Rows[0]["IS_NEED_INPUT"]) == WfFieldCode.DbTrue)
            {
                //在需要输入值的条件下 如果输入值为空并且数据库中输入值也为空 失败返回
                if (inputValue == null && dt.Rows[0]["INPUT_VALUE"] == DBNull.Value)
                {
                    return; //如果数据库里面需要输入值 而这里没有提供 则直接返回
                }
                inputValue = inputValue ?? int.Parse(dt.Rows[0]["INPUT_VALUE"].ToString());
                parm = dt.Rows[0]["PARA_NAME"].ToString().Trim();
                parm = string.Format(@"{0}:{1}", parm, inputValue);
            }

            int ident = -1;
            var logic = new WfConditionParser();
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                //那么就计算一下逻辑表达式是否为false
                if (!logic.ParseCondition(dt.Rows[i]["EXPRESS"].ToString(), parm)) continue;
                ident = i;
                break;
            }

            // 如果有一条为真
            //结束当前活动,并且启动下一活动
            if (ident != -1)
            {
                act.IsLocked = WfFieldCode.DbTrue;
                if (act.Run() && act.Complete())
                {
                    act.Status = WfFieldCode.DbCompleteState;
                }
                
                //启动下一个活动
                if (dt.Rows[ident]["NEXTACT"] == DBNull.Value) return;

                //--------------activate dt.Rows[0]["NEXTACT"] act
                var obj = new[]
                {
                    new OracleParameter("var_actid", OracleDbType.Int32) {Value = Convert.ToInt32(dt.Rows[ident]["NEXTACT"])}, //0
                    new OracleParameter("var_activator", OracleDbType.Int32) {Value = act.ID}, //1
                    new OracleParameter("var_influenceRows", OracleDbType.Int32, ParameterDirection.Output) //2
                };
                DB.ExecuteProc("ActivateAct", obj);
            }
            else
            {
                act.Ready(activatorID); //如果都为假则终止
            }

            #endregion 判断要选择的路径或要设置的路径
        }
    }
}